/*
<Copyright (C) 2011 Dru Moore>

This file is part of demorecorder.

vlc-remote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

demorecorder is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with demorecorder.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "mixerpipeline.h"
#include "utilities.h"
#include <QDebug>
#include <QDateTime>

MixerPipeline::MixerPipeline(QObject *parent) :
    QObject(parent)
{
    MixerPipeline(parent, "");
}

MixerPipeline::MixerPipeline(QObject *parent, QString name) :
    QObject(parent)
{
    this->name = name;
    this->position = 0;
    this->duration = 0;
    //define the queries
    duration_query = gst_query_new_duration(GST_FORMAT_TIME);
    position_query = gst_query_new_position(GST_FORMAT_TIME);
   // qDebug("pre construct");
    this->construct_pipeline();
}

void MixerPipeline::construct_pipeline() {
    this->pipeline = GST_PIPELINE(gst_pipeline_new("pipeline"));
    g_assert(this->pipeline);

    this->adder = gst_element_factory_make("adder", "adder");
    g_assert(this->adder); // chances are if this fails then gstreamer0.10-plugins-base-extra is missing from the device

    this->panorama = gst_element_factory_make("audiopanorama", "panorama");
    Utilities::setGObjectProperty(G_OBJECT(this->panorama), "panorama", 0.0);
    g_assert(this->panorama);

    this->volume = gst_element_factory_make("volume", "volume");
    g_assert(this->volume);
    Utilities::setGObjectProperty(G_OBJECT(this->volume), "volume", 1.0);
    Utilities::setGObjectProperty(G_OBJECT(this->volume), "mute", false);

    this->audio_sink = gst_element_factory_make("autoaudiosink", "audiosink");
    g_assert(this->audio_sink);

    gst_bin_add_many(GST_BIN(this->pipeline), this->adder, this->panorama, this->volume, this->audio_sink, NULL);
    if (gst_element_link_many(this->adder, this->panorama, this->volume, this->audio_sink, NULL)) {
        qDebug() << "mixer pipeline created fine.";
    }
    else {
        qDebug() << "mixer pipeline failed to create.";
    }

}

bool MixerPipeline::add_track(QString name, GstElement *track) {
    gst_bin_add(GST_BIN(this->pipeline), track);
    return gst_element_link(track, this->adder);
}

bool MixerPipeline::remove_track(QString name) {
    // find the track by name and call remove_track
    bool ret = false;
    GstElement *track = gst_bin_get_by_name(GST_BIN(this->pipeline), ("track_bin_" + name).toLatin1());
    if (NULL != track) {
        ret = remove_track(track);
        //delete track;
    }
    return ret;
}

bool MixerPipeline::remove_track(GstElement *track) {
    //this->stop();
    gst_element_set_state(GST_ELEMENT(this->pipeline), GST_STATE_READY);
    gst_element_unlink(GST_ELEMENT(track), GST_ELEMENT(this->adder));
    return gst_bin_remove(GST_BIN(this->pipeline), GST_ELEMENT(track));
    gst_element_set_state(GST_ELEMENT(this->pipeline), GST_STATE_PAUSED);
}

gboolean MixerPipeline::bus_callback(GstBus *bus, GstMessage *message, void* data) {
    //Q_UNUSED(bus);
    //Q_UNUSED(data);
    qDebug("bus_callback called");
    switch (GST_MESSAGE_TYPE(message)) {
        case GST_MESSAGE_EOS:
        qDebug("eos");
            ((MixerPipeline*)data)->end_of_stream();
            break;
        case GST_MESSAGE_ERROR:
        qDebug("error");
            break;
        case GST_MESSAGE_STATE_CHANGED:
        qDebug("state changed");
            break;
        default:
            break;
    }
    return true;
}

void MixerPipeline::get_duration_info() {
    //qDebug("get_duration_info requested");
    bool duration_result,position_result;
    duration_result = gst_element_query(GST_ELEMENT(this->pipeline), this->duration_query);
    position_result = gst_element_query(GST_ELEMENT(this->pipeline), this->position_query);
    if ( duration_result && position_result  ) {
        //qDebug("got a result");
        gint64 pos;
        gint64 dur;
        gst_query_parse_duration(this->duration_query, NULL, &dur);
        gst_query_parse_position(this->position_query, NULL, &pos);
        this->duration =(long long) dur;
        this->position =(long long) pos;
        emit this->position_duration(this->position, this->duration);
        if (this->position >= this->duration) {
            emit this->end_of_stream();
        }
    }
    else {
        //qDebug("no result. try again");
    }
}

long long MixerPipeline::get_current_time() {
    QDateTime setTime = QDateTime::fromString (QString("1970-07-18T14:15:09"), Qt::ISODate);
    QDateTime current = QDateTime::currentDateTime();
    return setTime.time().msecsTo(current.time());
}

void MixerPipeline::play() {
    GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT(this->pipeline), GST_STATE_PLAYING);
    qDebug() << "status change play " << ret;
}

void MixerPipeline::pause() {
    GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT(this->pipeline), GST_STATE_PAUSED);
    qDebug() << "status change pause " << ret;
}

void MixerPipeline::stop() {
    GstStateChangeReturn ret = gst_element_set_state(GST_ELEMENT(this->pipeline), GST_STATE_READY);
    qDebug() << "status change stop " << ret;
}

void MixerPipeline::seekTo(long long position) {
    gst_element_seek(GST_ELEMENT(this->pipeline), 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
}
